Stringify any JavaScript value.
- Serialize built-in JavaScript types.
- Serialize application-specific data types with built-in or user-defined plugins.
$ yarn add pretty-format
const {format: prettyFormat} = require('pretty-format'); // CommonJS
import {format as prettyFormat} from 'pretty-format'; // ES2015 modules
const val = {object: {}};
val.circularReference = val;
val[Symbol('foo')] = 'foo';
val.map = new Map([['prop', 'value']]);
val.array = [-0, Infinity, NaN];
console.log(prettyFormat(val));
/*
Object {
"array": Array [
-0,
Infinity,
NaN,
],
"circularReference": [Circular],
"map": Map {
"prop" => "value",
},
"object": Object {},
Symbol(foo): "foo",
}
*/
function onClick() {}
console.log(prettyFormat(onClick));
/*
[Function onClick]
*/
const options = {
printFunctionName: false,
};
console.log(prettyFormat(onClick, options));
/*
[Function]
*/
key | type | default | description |
---|---|---|---|
callToJSON |
boolean |
true |
call toJSON method (if it exists) on objects |
compareKeys |
function|null |
undefined |
compare function used when sorting object keys, null can be used to skip over sorting |
escapeRegex |
boolean |
false |
escape special characters in regular expressions |
escapeString |
boolean |
true |
escape special characters in strings |
highlight |
boolean |
false |
highlight syntax with colors in terminal (some plugins) |
indent |
number |
2 |
spaces in each level of indentation |
maxDepth |
number |
Infinity |
levels to print in arrays, objects, elements, and so on |
maxWidth |
number |
Infinity |
number of elements to print in arrays, sets, and so on |
min |
boolean |
false |
minimize added space: no indentation nor line breaks |
plugins |
array |
[] |
plugins to serialize application-specific data types |
printBasicPrototype |
boolean |
false |
print the prototype for plain objects and arrays |
printFunctionName |
boolean |
true |
include or omit the name of a function |
theme |
object |
colors to highlight syntax in terminal |
Property values of theme
are from ansi-styles colors
const DEFAULT_THEME = {
comment: 'gray',
content: 'reset',
prop: 'yellow',
tag: 'cyan',
value: 'green',
};
The pretty-format
package provides some built-in plugins, including:
-
ReactElement
for elements fromreact
-
ReactTestComponent
for test objects fromreact-test-renderer
// CommonJS
const React = require('react');
const renderer = require('react-test-renderer');
const {format: prettyFormat, plugins} = require('pretty-format');
const {ReactElement, ReactTestComponent} = plugins;
// ES2015 modules and destructuring assignment
import React from 'react';
import renderer from 'react-test-renderer';
import {plugins, format as prettyFormat} from 'pretty-format';
const {ReactElement, ReactTestComponent} = plugins;
const onClick = () => {};
const element = React.createElement('button', {onClick}, 'Hello World');
const formatted1 = prettyFormat(element, {
plugins: [ReactElement],
printFunctionName: false,
});
const formatted2 = prettyFormat(renderer.create(element).toJSON(), {
plugins: [ReactTestComponent],
printFunctionName: false,
});
/*
<button
onClick=[Function]
>
Hello World
</button>
*/
For snapshot tests, Jest uses pretty-format
with options that include some of its built-in plugins. For this purpose, plugins are also known as snapshot serializers.
To serialize application-specific data types, you can add modules to devDependencies
of a project, and then:
In an individual test file, you can add a module as follows. It precedes any modules from Jest configuration.
import serializer from 'my-serializer-module';
expect.addSnapshotSerializer(serializer);
// tests which have `expect(value).toMatchSnapshot()` assertions
For all test files, you can specify modules in Jest configuration. They precede built-in plugins for React, HTML, and Immutable.js data types. For example, in a package.json
file:
{
"jest": {
"snapshotSerializers": ["my-serializer-module"]
}
}
A plugin is a JavaScript object.
If options
has a plugins
array: for the first plugin whose test(val)
method returns a truthy value, then prettyFormat(val, options)
returns the result from either:
-
serialize(val, …)
method of the improved interface (available in version 21 or later) -
print(val, …)
method of the original interface (if plugin does not haveserialize
method)
Write test
so it can receive val
argument of any type. To serialize objects which have certain properties, then a guarded expression like val != null && …
or more concise val && …
prevents the following errors:
TypeError: Cannot read property 'whatever' of null
TypeError: Cannot read property 'whatever' of undefined
For example, test
method of built-in ReactElement
plugin:
const elementSymbol = Symbol.for('react.element');
const test = val => val && val.$$typeof === elementSymbol;
Pay attention to efficiency in test
because pretty-format
calls it often.
The improved interface is available in version 21 or later.
Write serialize
to return a string, given the arguments:
-
val
which “passed the test” - unchanging
config
object: derived fromoptions
- current
indentation
string: concatenate toindent
fromconfig
- current
depth
number: compare tomaxDepth
fromconfig
- current
refs
array: find circular references in objects -
printer
callback function: serialize children
key | type | description |
---|---|---|
callToJSON |
boolean |
call toJSON method (if it exists) on objects |
compareKeys |
function|null |
compare function used when sorting object keys, null can be used to skip over sorting |
colors |
Object |
escape codes for colors to highlight syntax |
escapeRegex |
boolean |
escape special characters in regular expressions |
escapeString |
boolean |
escape special characters in strings |
indent |
string |
spaces in each level of indentation |
maxDepth |
number |
levels to print in arrays, objects, elements, and so on |
min |
boolean |
minimize added space: no indentation nor line breaks |
plugins |
array |
plugins to serialize application-specific data types |
printFunctionName |
boolean |
include or omit the name of a function |
spacingInner |
string |
spacing to separate items in a list |
spacingOuter |
string |
spacing to enclose a list of items |
Each property of colors
in config
corresponds to a property of theme
in options
:
- the key is the same (for example,
tag
) - the value in
colors
is a object withopen
andclose
properties whose values are escape codes from ansi-styles for the color value intheme
(for example,'cyan'
)
Some properties in config
are derived from min
in options
:
-
spacingInner
andspacingOuter
are newline ifmin
isfalse
-
spacingInner
is space andspacingOuter
is empty string ifmin
istrue
This plugin is a pattern you can apply to serialize composite data types. Side note: pretty-format
does not need a plugin to serialize arrays.
// We reused more code when we factored out a function for child items
// that is independent of depth, name, and enclosing punctuation (see below).
const SEPARATOR = ',';
function serializeItems(items, config, indentation, depth, refs, printer) {
if (items.length === 0) {
return '';
}
const indentationItems = indentation + config.indent;
return (
config.spacingOuter +
items
.map(
item =>
indentationItems +
printer(item, config, indentationItems, depth, refs), // callback
)
.join(SEPARATOR + config.spacingInner) +
(config.min ? '' : SEPARATOR) + // following the last item
config.spacingOuter +
indentation
);
}
const plugin = {
test(val) {
return Array.isArray(val);
},
serialize(array, config, indentation, depth, refs, printer) {
const name = array.constructor.name;
return ++depth > config.maxDepth
? `[${name}]`
: `${config.min ? '' : `${name} `}[${serializeItems(
array,
config,
indentation,
depth,
refs,
printer,
)}]`;
},
};
const val = {
filter: 'completed',
items: [
{
text: 'Write test',
completed: true,
},
{
text: 'Write serialize',
completed: true,
},
],
};
console.log(
prettyFormat(val, {
plugins: [plugin],
}),
);
/*
Object {
"filter": "completed",
"items": Array [
Object {
"completed": true,
"text": "Write test",
},
Object {
"completed": true,
"text": "Write serialize",
},
],
}
*/
console.log(
prettyFormat(val, {
indent: 4,
plugins: [plugin],
}),
);
/*
Object {
"filter": "completed",
"items": Array [
Object {
"completed": true,
"text": "Write test",
},
Object {
"completed": true,
"text": "Write serialize",
},
],
}
*/
console.log(
prettyFormat(val, {
maxDepth: 1,
plugins: [plugin],
}),
);
/*
Object {
"filter": "completed",
"items": [Array],
}
*/
console.log(
prettyFormat(val, {
min: true,
plugins: [plugin],
}),
);
/*
{"filter": "completed", "items": [{"completed": true, "text": "Write test"}, {"completed": true, "text": "Write serialize"}]}
*/
The original interface is adequate for plugins:
- that do not depend on options other than
highlight
ormin
- that do not depend on
depth
orrefs
in recursive traversal, and - if values either
- do not require indentation, or
- do not occur as children of JavaScript data structures (for example, array)
Write print
to return a string, given the arguments:
-
val
which “passed the test” - current
printer(valChild)
callback function: serialize children - current
indenter(lines)
callback function: indent lines at the next level - unchanging
config
object: derived fromoptions
- unchanging
colors
object: derived fromoptions
The 3 properties of config
are min
in options
and:
-
spacing
andedgeSpacing
are newline ifmin
isfalse
-
spacing
is space andedgeSpacing
is empty string ifmin
istrue
Each property of colors
corresponds to a property of theme
in options
:
- the key is the same (for example,
tag
) - the value in
colors
is a object withopen
andclose
properties whose values are escape codes from ansi-styles for the color value intheme
(for example,'cyan'
)
This plugin prints functions with the number of named arguments excluding rest argument.
const plugin = {
print(val) {
return `[Function ${val.name || 'anonymous'} ${val.length}]`;
},
test(val) {
return typeof val === 'function';
},
};
const val = {
onClick(event) {},
render() {},
};
prettyFormat(val, {
plugins: [plugin],
});
/*
Object {
"onClick": [Function onClick 1],
"render": [Function render 0],
}
*/
prettyFormat(val);
/*
Object {
"onClick": [Function onClick],
"render": [Function render],
}
*/
This plugin ignores the printFunctionName
option. That limitation of the original print
interface is a reason to use the improved serialize
interface, described above.
prettyFormat(val, {
plugins: [pluginOld],
printFunctionName: false,
});
/*
Object {
"onClick": [Function onClick 1],
"render": [Function render 0],
}
*/
prettyFormat(val, {
printFunctionName: false,
});
/*
Object {
"onClick": [Function],
"render": [Function],
}
*/